Welcome to my notebook covering the use of the tidycensus R package for extracting and evaluating census data in the state of Oregon. In part A We are interested in uncovering the percentages of the population with graduate level degrees at a county level. Part B will continue to focus on education data, Stay tuned to find out more!

Import Libraries

Start by importing the list of libraries that will assist us in connecting with the Census Bureau’s APIs and visualizing the desired data.
library(tidycensus) # connect with the census bureau API
library(tidyverse) # data wrangling
library(mapview) # spatial data visualizer
library(plotly) # graph / chart visualizer
library(ggiraph) # graph / chart visualizer
library(ggplot2) # graph / chart visualizer
library(DT) # fancy tables
library(scales) # scales map data to aesthetics
library(sf) # spatial data package
library(tigris) # erase water
library(cowplot) # plot_grid()

Part A


Data Source

We will use the get_acs() function from the tidycensus package to pull data from the census bureau. The function defaults to the 2017-2021 5-year ACS dataset. Which is necessary for us, since there are a list of counties in Oregon with a population of less than 65,000.
The data we would like to visualize is the percent of the population that have a graduate degree at the county level in the state of Oregon.
# use the get_acs() function for importing data
or_grads <- get_acs(
  geography = "county", # county level geography
  variables = "DP02_0066P", # variable for percent of the population that have a graduate degrees
  state = "OR", 
  year = 2021,
  progress_bar = FALSE
)

Data Manipulation & DataTables

An important aspect of the tidycensus package is that is presents the data to us in a tidy format. The data is pre-cleaned and takes little wrangling to answer questions.
# filter and arrange results
or_grads_table <- or_grads %>%
  separate(NAME, into = c("county", "state"), sep = ", ") %>% # create county and state columns
  arrange(-estimate) %>% # sort by estimate descending
  select(county, state, estimate, moe) # select important columns
By using the datatable() function from the DT library we can filter our results to see the desired information.
# function from the DT library to create a datatable
datatable(or_grads_table)

Figure 1 above reveals the data imported from the get_acs() function. Results conclude that the top 3 counties with graduate degrees is Benton, Multnomah, and Washington. Bottom 3 counties are Malheur, Gilliam, and Morrow.


Data Visualization & Analysis

Now that our data is imported and in a proper format. We can begin using ggplot to visualize the percentage of the oregon population that graduate have degrees.
# use ggplot with estimate as the x axis and county as the y axis
or_plot <- ggplot(or_grads_table, aes(x = estimate, 
                                      y = reorder(county, estimate))) + # sort by counties high to low
  geom_point(color="navy", size = 3) + # state color navy blue for point data
  scale_x_continuous(labels = function(x) paste0(x, '%')) + # concatenate '%' to estimate data
  scale_y_discrete(labels = function(x) str_remove(x, " County")) + # strip 'county' from the name column
  labs(title = "% Population with graduate degrees, 2017-2021 ACS", # use appropriate title
       subtitle = "Counties in Oregon", # use appropriate subtitle
       caption = "Data acquired with R and tidycensus",
       x = "ACS estimate Percentage",
       y = "") +
  theme_minimal(base_size = 12) # remove tick marks 
  
or_plot # print plot

Figure 2 above plots the counties by estimate value in a descending order. We get a full picture of our results without having to filter through multiple pages in a table.


All tables in the tidycensus package come with a margin of error column to give us an understanding of accuracy in the dataset. Typically, census data from geographies of larger population have a lower margin of error.
Lets plot the MOE variable with our estimate variable below.
# create plot revealing moe and estimate variables
or_plot_errorbar <- ggplot(or_grads, aes(x = estimate, y = reorder(NAME, estimate))) + # sort by counties high to low
  geom_errorbar(aes(xmin = estimate - moe, xmax = estimate + moe), 
                width = 0.5, linewidth = 0.5) +
  geom_point(color = "gold", size = 3) + # state color gold for point data
  scale_x_continuous(labels = function(x) paste0(x, '%')) + # concatenate '%' to estimate data
  scale_y_discrete(labels = function(x) str_remove(x, " County, Oregon|, Oregon")) + # strip 'county' from the name column
  labs(title = "% Population with graduate degrees, 2017-2021 ACS", # use appropriate title
       subtitle = "Counties in Oregon", # use appropriate subtitle
       caption = "Data acquired with R and tidycensus. Error bars represent margin of error around estimates.",
       "ACS estimate",
      y = "",
      x = "Percentage") +
  theme_minimal(base_size = 12) # remove tick marks 
  
or_plot_errorbar # print plot

Figure 3 above reveals the margin of error associated with the estimate data.


Interative Plots

Using ggplotly() I’m going to recreate the plot above but leveraging the interactivity of the plotly library.
# use ggplotly() and add a tooltip, and extend the margins of the plot
ggplotly(or_plot_errorbar, tooltip = "x")%>% 
  layout(margin = list(l = 50, r = 50, b = 50, t = 50))

Figure 4 Hover over the points in the plot above to see the interactive tootip.


Part B


Continuing with the theme of education, lets import more data through the tidycensus package.
What percentage of people with bachelor’s degrees rent or own their home in Washington and Multnomah County, Oregon at the tract level?
These two counties together cover the most populus city of Oregon. You guessed it, Portland.
To find variables that will assist us in our analysis, we will use the load_variables() function to filter through the ACS data.
# use the load_variables function() with the year and ACS 5 year parameter
vars <- load_variables(2021, "acs5")
# load vars into a datatable
datatable(vars)

Figure 5 By using the search feature in the datatable, you see examples of available results. For example search “bachelor’s” to find variable codes moving forward.


Import Data

We will need to pull in two datasets and eventually merge the results into one table.
“B25013_006” is the population of people with bachelor’s degrees that own their home.
“B25013_011” is the population of people with bachelor’s degrees that rent their home.
# import data at the tract level for home owners
bach_owners <- erase_water(get_acs(
  geography = "tract",
  variables = "B25013_006",
  state = "OR",
  county = c("Washington", "Multnomah"), # select multiple counties
  geometry = TRUE, # get multipolygon data of Oregon tracts
  progress_bar = FALSE
))

# import data at the tract level for renters
bach_renters <- get_acs(
  geography = "tract",
  variables = "B25013_011",
  state = "OR",
  county = c("Washington", "Multnomah"), # select multiple counties
  geometry = FALSE, # geometry is false because we are getting our multipolygon data in the owners dataset. 
  progress_bar = FALSE
  )

Data Wrangling

Use functions of the tidyverse to rename, select, and mutuate columns to fit our analysis. Since the estimate data originally comes as a count, we will sum up renters and owners to a create a total column and a percentage column for each.
# clarify the name of the estimate & moe columns before joining
bach_owners <- bach_owners %>%
  rename(estimate_owners = estimate, moe_owners = moe)

# clarify the name of the estimate & moe columns before joining
bach_renters <- bach_renters %>%
  rename(estimate_renters = estimate, moe_renters = moe) %>%
  select(GEOID, estimate_renters, moe_renters) # drop unnecessary values

# join dataframes on GEOID, and create percent columns of each category
bach_housing <- left_join(bach_owners, bach_renters, by='GEOID') %>%
  select(GEOID, NAME, estimate_owners, estimate_renters, moe_owners, moe_renters, geometry) %>%
  mutate(estimate_total = estimate_renters + estimate_owners) %>% # create a total value
  mutate(percent_renters = (estimate_renters/estimate_total)*100) %>% # create a % of renters
  mutate(percent_owners = (estimate_owners/estimate_total)*100) %>% # create a % of owners
  mutate(across(where(is.numeric), ~ round(.x, digits = 2)))
Error in exists(cacheKey, where = .rs.WorkingDataEnv, inherits = FALSE) : 
  invalid first argument
Error in assign(cacheKey, frame, .rs.CachedDataEnv) : 
  attempt to use zero-length variable name

Data Visualization & Analysis

Now that the data is wrangled we can view it in a table before mapping and plotting the desired variables.
# select percent renters and owners
bach_housing_table <- bach_housing %>%
  select(NAME, percent_renters, percent_owners) %>%
  arrange(-percent_renters) # arrange in descending order

# preview in datatable
datatable(bach_housing_table)

Figure 6 As suspected in Portland there are a high number of renters with bachelor’s degrees. Multiple tracts reveal areas with 100% of our particular study rent their homes.

We are going to start with the mapview package to get a glimplse into the data.
# use the percent_renters variable to display in the mapview
mapview(bach_housing,
        layer.name = "% Renters<br/>2017-2021 ACS", # change layer name
        zcol = "percent_renters") # select a variable to display

Figure 7 Mapview is programmtically a simple way to display insightful and interactive data. We can now easiy visualize that the city center has the highest number of renters versus owners and shifts as you move into the more rural areas.

Now that we have sampled the data in mapview, lets use ggplot to create a set of chloropleth maps for both categories (renting and owning).
# create ggplot for renters
renters <- ggplot(bach_housing, aes(fill = percent_renters)) + # fill with percent renters
  geom_sf() + 
  theme_void() + 
  scale_fill_viridis_c(option = "rocket") + # use rocket color scheme
  labs(title = "Percent of Population w/ Bachelor's Degree Renting by Census tract", # create clear titles and captions
       subtitle = "Washington & Multnomah County, Oregon",
       fill = "% Renting",
       caption = "2017-2021 ACS | tidycensus R package")

# create ggplot for owners
owners <- ggplot(bach_housing, aes(fill = percent_owners)) + 
  geom_sf() + 
  theme_void() + 
  scale_fill_viridis_c(option = "rocket") +  # use rocket color scheme
  labs(title = "Percent of Population w/ Bachelor's Degree That Own Their Home by Census tract",  # create clear titles and captions
       subtitle = "Washington & Multnomah County, Oregon",
       fill = "% Owners",
       caption = "2017-2021 ACS | tidycensus R package")

# use plot_grid from the cowplot library to stack the maps
plot_grid(renters, owners, ncol=1, align = "hv")

Figure 8 The last figure paints a clear picture of the city center vs rural areas in terms of the ability to own a home in the Portland Metro area.



LS0tDQp0aXRsZTogIkVkdWNhdGlvbiBTdGF0aXN0aWNzIGluIE9yZWdvbiAtIEFsaXMgdm9sYXQgcHJvcHJpaXMiDQpvdXRwdXQ6DQogIGh0bWxfZG9jdW1lbnQ6DQogICAgZGZfcHJpbnQ6IHBhZ2VkDQotLS0NCiMjIyMgV2VsY29tZSB0byBteSBub3RlYm9vayBjb3ZlcmluZyB0aGUgdXNlIG9mIHRoZSB0aWR5Y2Vuc3VzIFIgcGFja2FnZSBmb3IgZXh0cmFjdGluZyBhbmQgZXZhbHVhdGluZyBjZW5zdXMgZGF0YSBpbiB0aGUgc3RhdGUgb2YgT3JlZ29uLiBJbiBwYXJ0IEEgV2UgYXJlIGludGVyZXN0ZWQgaW4gdW5jb3ZlcmluZyB0aGUgcGVyY2VudGFnZXMgb2YgdGhlIHBvcHVsYXRpb24gd2l0aCBncmFkdWF0ZSBsZXZlbCBkZWdyZWVzIGF0IGEgY291bnR5IGxldmVsLiBQYXJ0IEIgd2lsbCBjb250aW51ZSB0byBmb2N1cyBvbiBlZHVjYXRpb24gZGF0YSwgU3RheSB0dW5lZCB0byBmaW5kIG91dCBtb3JlIQ0KDQojIyMgSW1wb3J0IExpYnJhcmllcw0KDQojIyMjIyBTdGFydCBieSBpbXBvcnRpbmcgdGhlIGxpc3Qgb2YgbGlicmFyaWVzIHRoYXQgd2lsbCBhc3Npc3QgdXMgaW4gY29ubmVjdGluZyB3aXRoIHRoZSBDZW5zdXMgQnVyZWF1J3MgQVBJcyBhbmQgdmlzdWFsaXppbmcgdGhlIGRlc2lyZWQgZGF0YS4gDQpgYGB7Y3NzLCBlY2hvPUZBTFNFfQ0KcCB7DQogIG1hcmdpbi1ib3R0b206IDBweDsNCn0NCmBgYA0KYGBge3IgbWVzc2FnZSA9IEZBTFNFLCB3YXJuaW5nID0gRkFMU0V9DQpsaWJyYXJ5KHRpZHljZW5zdXMpICMgY29ubmVjdCB3aXRoIHRoZSBjZW5zdXMgYnVyZWF1IEFQSQ0KbGlicmFyeSh0aWR5dmVyc2UpICMgZGF0YSB3cmFuZ2xpbmcNCmxpYnJhcnkobWFwdmlldykgIyBzcGF0aWFsIGRhdGEgdmlzdWFsaXplcg0KbGlicmFyeShwbG90bHkpICMgZ3JhcGggLyBjaGFydCB2aXN1YWxpemVyDQpsaWJyYXJ5KGdnaXJhcGgpICMgZ3JhcGggLyBjaGFydCB2aXN1YWxpemVyDQpsaWJyYXJ5KGdncGxvdDIpICMgZ3JhcGggLyBjaGFydCB2aXN1YWxpemVyDQpsaWJyYXJ5KERUKSAjIGZhbmN5IHRhYmxlcw0KbGlicmFyeShzY2FsZXMpICMgc2NhbGVzIG1hcCBkYXRhIHRvIGFlc3RoZXRpY3MNCmxpYnJhcnkoc2YpICMgc3BhdGlhbCBkYXRhIHBhY2thZ2UNCmxpYnJhcnkodGlncmlzKSAjIGVyYXNlIHdhdGVyDQpsaWJyYXJ5KGNvd3Bsb3QpICMgcGxvdF9ncmlkKCkNCmBgYA0KIyMjIFBhcnQgQQ0KPGhyIC8+DQojIyMgRGF0YSBTb3VyY2UNCg0KIyMjIyMgV2Ugd2lsbCB1c2UgdGhlIGdldF9hY3MoKSBmdW5jdGlvbiBmcm9tIHRoZSB0aWR5Y2Vuc3VzIHBhY2thZ2UgdG8gcHVsbCBkYXRhIGZyb20gdGhlIGNlbnN1cyBidXJlYXUuIFRoZSBmdW5jdGlvbiBkZWZhdWx0cyB0byB0aGUgMjAxNy0yMDIxIDUteWVhciBBQ1MgZGF0YXNldC4gV2hpY2ggaXMgbmVjZXNzYXJ5IGZvciB1cywgc2luY2UgdGhlcmUgYXJlIGEgbGlzdCBvZiBjb3VudGllcyBpbiBPcmVnb24gd2l0aCBhIHBvcHVsYXRpb24gb2YgbGVzcyB0aGFuIDY1LDAwMC4gDQoNCiMjIyMjIFRoZSBkYXRhIHdlIHdvdWxkIGxpa2UgdG8gdmlzdWFsaXplIGlzIHRoZSBwZXJjZW50IG9mIHRoZSBwb3B1bGF0aW9uIHRoYXQgaGF2ZSBhIGdyYWR1YXRlIGRlZ3JlZSBhdCB0aGUgY291bnR5IGxldmVsIGluIHRoZSBzdGF0ZSBvZiBPcmVnb24uICANCmBgYHtyIG1lc3NhZ2UgPSBGQUxTRSwgd2FybmluZyA9IEZBTFNFfQ0KIyB1c2UgdGhlIGdldF9hY3MoKSBmdW5jdGlvbiBmb3IgaW1wb3J0aW5nIGRhdGENCm9yX2dyYWRzIDwtIGdldF9hY3MoDQogIGdlb2dyYXBoeSA9ICJjb3VudHkiLCAjIGNvdW50eSBsZXZlbCBnZW9ncmFwaHkNCiAgdmFyaWFibGVzID0gIkRQMDJfMDA2NlAiLCAjIHZhcmlhYmxlIGZvciBwZXJjZW50IG9mIHRoZSBwb3B1bGF0aW9uIHRoYXQgaGF2ZSBhIGdyYWR1YXRlIGRlZ3JlZXMNCiAgc3RhdGUgPSAiT1IiLCANCiAgeWVhciA9IDIwMjEsDQogIHByb2dyZXNzX2JhciA9IEZBTFNFDQopDQpgYGANCiMjIyBEYXRhIE1hbmlwdWxhdGlvbiAmIERhdGFUYWJsZXMNCg0KIyMjIyMgQW4gaW1wb3J0YW50IGFzcGVjdCBvZiB0aGUgdGlkeWNlbnN1cyBwYWNrYWdlIGlzIHRoYXQgaXMgcHJlc2VudHMgdGhlIGRhdGEgdG8gdXMgaW4gYSB0aWR5IGZvcm1hdC4gVGhlIGRhdGEgaXMgcHJlLWNsZWFuZWQgYW5kIHRha2VzIGxpdHRsZSB3cmFuZ2xpbmcgdG8gYW5zd2VyIHF1ZXN0aW9ucy4NCmBgYHtyfQ0KIyBmaWx0ZXIgYW5kIGFycmFuZ2UgcmVzdWx0cw0Kb3JfZ3JhZHNfdGFibGUgPC0gb3JfZ3JhZHMgJT4lDQogIHNlcGFyYXRlKE5BTUUsIGludG8gPSBjKCJjb3VudHkiLCAic3RhdGUiKSwgc2VwID0gIiwgIikgJT4lICMgY3JlYXRlIGNvdW50eSBhbmQgc3RhdGUgY29sdW1ucw0KICBhcnJhbmdlKC1lc3RpbWF0ZSkgJT4lICMgc29ydCBieSBlc3RpbWF0ZSBkZXNjZW5kaW5nDQogIHNlbGVjdChjb3VudHksIHN0YXRlLCBlc3RpbWF0ZSwgbW9lKSAjIHNlbGVjdCBpbXBvcnRhbnQgY29sdW1ucw0KYGBgDQoNCiMjIyMjIEJ5IHVzaW5nIHRoZSBkYXRhdGFibGUoKSBmdW5jdGlvbiBmcm9tIHRoZSBEVCBsaWJyYXJ5IHdlIGNhbiBmaWx0ZXIgb3VyIHJlc3VsdHMgdG8gc2VlIHRoZSBkZXNpcmVkIGluZm9ybWF0aW9uLg0KYGBge3J9DQojIGZ1bmN0aW9uIGZyb20gdGhlIERUIGxpYnJhcnkgdG8gY3JlYXRlIGEgZGF0YXRhYmxlDQpkYXRhdGFibGUob3JfZ3JhZHNfdGFibGUpDQpgYGANCioqRmlndXJlIDEqKiBhYm92ZSByZXZlYWxzIHRoZSBkYXRhIGltcG9ydGVkIGZyb20gdGhlIGdldF9hY3MoKSBmdW5jdGlvbi4gUmVzdWx0cyBjb25jbHVkZSB0aGF0IHRoZSB0b3AgMyBjb3VudGllcyB3aXRoIGdyYWR1YXRlIGRlZ3JlZXMgaXMgQmVudG9uLCBNdWx0bm9tYWgsIGFuZCBXYXNoaW5ndG9uLiBCb3R0b20gMyBjb3VudGllcyBhcmUgTWFsaGV1ciwgR2lsbGlhbSwgYW5kIE1vcnJvdy4NCg0KPGhyIC8+DQoNCiMjIyBEYXRhIFZpc3VhbGl6YXRpb24gJiBBbmFseXNpcw0KDQojIyMjIyBOb3cgdGhhdCBvdXIgZGF0YSBpcyBpbXBvcnRlZCBhbmQgaW4gYSBwcm9wZXIgZm9ybWF0LiBXZSBjYW4gYmVnaW4gdXNpbmcgZ2dwbG90IHRvIHZpc3VhbGl6ZSB0aGUgcGVyY2VudGFnZSBvZiB0aGUgb3JlZ29uIHBvcHVsYXRpb24gdGhhdCBncmFkdWF0ZSBoYXZlIGRlZ3JlZXMuIA0KYGBge3IgZmlnLmhlaWdodD02LCBmaWcud2lkdGg9OS41fQ0KIyB1c2UgZ2dwbG90IHdpdGggZXN0aW1hdGUgYXMgdGhlIHggYXhpcyBhbmQgY291bnR5IGFzIHRoZSB5IGF4aXMNCm9yX3Bsb3QgPC0gZ2dwbG90KG9yX2dyYWRzX3RhYmxlLCBhZXMoeCA9IGVzdGltYXRlLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeSA9IHJlb3JkZXIoY291bnR5LCBlc3RpbWF0ZSkpKSArICMgc29ydCBieSBjb3VudGllcyBoaWdoIHRvIGxvdw0KICBnZW9tX3BvaW50KGNvbG9yPSJuYXZ5Iiwgc2l6ZSA9IDMpICsgIyBzdGF0ZSBjb2xvciBuYXZ5IGJsdWUgZm9yIHBvaW50IGRhdGENCiAgc2NhbGVfeF9jb250aW51b3VzKGxhYmVscyA9IGZ1bmN0aW9uKHgpIHBhc3RlMCh4LCAnJScpKSArICMgY29uY2F0ZW5hdGUgJyUnIHRvIGVzdGltYXRlIGRhdGENCiAgc2NhbGVfeV9kaXNjcmV0ZShsYWJlbHMgPSBmdW5jdGlvbih4KSBzdHJfcmVtb3ZlKHgsICIgQ291bnR5IikpICsgIyBzdHJpcCAnY291bnR5JyBmcm9tIHRoZSBuYW1lIGNvbHVtbg0KICBsYWJzKHRpdGxlID0gIiUgUG9wdWxhdGlvbiB3aXRoIGdyYWR1YXRlIGRlZ3JlZXMsIDIwMTctMjAyMSBBQ1MiLCAjIHVzZSBhcHByb3ByaWF0ZSB0aXRsZQ0KICAgICAgIHN1YnRpdGxlID0gIkNvdW50aWVzIGluIE9yZWdvbiIsICMgdXNlIGFwcHJvcHJpYXRlIHN1YnRpdGxlDQogICAgICAgY2FwdGlvbiA9ICJEYXRhIGFjcXVpcmVkIHdpdGggUiBhbmQgdGlkeWNlbnN1cyIsDQogICAgICAgeCA9ICJBQ1MgZXN0aW1hdGUgUGVyY2VudGFnZSIsDQogICAgICAgeSA9ICIiKSArDQogIHRoZW1lX21pbmltYWwoYmFzZV9zaXplID0gMTIpICMgcmVtb3ZlIHRpY2sgbWFya3MgDQogIA0Kb3JfcGxvdCAjIHByaW50IHBsb3QNCmBgYA0KKipGaWd1cmUgMioqIGFib3ZlIHBsb3RzIHRoZSBjb3VudGllcyBieSBlc3RpbWF0ZSB2YWx1ZSBpbiBhIGRlc2NlbmRpbmcgb3JkZXIuIFdlIGdldCBhIGZ1bGwgcGljdHVyZSBvZiBvdXIgcmVzdWx0cyB3aXRob3V0IGhhdmluZyB0byBmaWx0ZXIgdGhyb3VnaCBtdWx0aXBsZSBwYWdlcyBpbiBhIHRhYmxlLg0KDQo8aHIgLz4NCg0KIyMjIyMgQWxsIHRhYmxlcyBpbiB0aGUgdGlkeWNlbnN1cyBwYWNrYWdlIGNvbWUgd2l0aCBhIG1hcmdpbiBvZiBlcnJvciBjb2x1bW4gdG8gZ2l2ZSB1cyBhbiB1bmRlcnN0YW5kaW5nIG9mIGFjY3VyYWN5IGluIHRoZSBkYXRhc2V0LiBUeXBpY2FsbHksIGNlbnN1cyBkYXRhIGZyb20gZ2VvZ3JhcGhpZXMgb2YgbGFyZ2VyIHBvcHVsYXRpb24gaGF2ZSBhIGxvd2VyIG1hcmdpbiBvZiBlcnJvci4NCg0KIyMjIyMgTGV0cyBwbG90IHRoZSBNT0UgdmFyaWFibGUgd2l0aCBvdXIgZXN0aW1hdGUgdmFyaWFibGUgYmVsb3cuIA0KYGBge3IgZmlnLmhlaWdodD02LCBmaWcud2lkdGg9OS41fQ0KIyBjcmVhdGUgcGxvdCByZXZlYWxpbmcgbW9lIGFuZCBlc3RpbWF0ZSB2YXJpYWJsZXMNCm9yX3Bsb3RfZXJyb3JiYXIgPC0gZ2dwbG90KG9yX2dyYWRzLCBhZXMoeCA9IGVzdGltYXRlLCB5ID0gcmVvcmRlcihOQU1FLCBlc3RpbWF0ZSkpKSArICMgc29ydCBieSBjb3VudGllcyBoaWdoIHRvIGxvdw0KICBnZW9tX2Vycm9yYmFyKGFlcyh4bWluID0gZXN0aW1hdGUgLSBtb2UsIHhtYXggPSBlc3RpbWF0ZSArIG1vZSksIA0KICAgICAgICAgICAgICAgIHdpZHRoID0gMC41LCBsaW5ld2lkdGggPSAwLjUpICsNCiAgZ2VvbV9wb2ludChjb2xvciA9ICJnb2xkIiwgc2l6ZSA9IDMpICsgIyBzdGF0ZSBjb2xvciBnb2xkIGZvciBwb2ludCBkYXRhDQogIHNjYWxlX3hfY29udGludW91cyhsYWJlbHMgPSBmdW5jdGlvbih4KSBwYXN0ZTAoeCwgJyUnKSkgKyAjIGNvbmNhdGVuYXRlICclJyB0byBlc3RpbWF0ZSBkYXRhDQogIHNjYWxlX3lfZGlzY3JldGUobGFiZWxzID0gZnVuY3Rpb24oeCkgc3RyX3JlbW92ZSh4LCAiIENvdW50eSwgT3JlZ29ufCwgT3JlZ29uIikpICsgIyBzdHJpcCAnY291bnR5JyBmcm9tIHRoZSBuYW1lIGNvbHVtbg0KICBsYWJzKHRpdGxlID0gIiUgUG9wdWxhdGlvbiB3aXRoIGdyYWR1YXRlIGRlZ3JlZXMsIDIwMTctMjAyMSBBQ1MiLCAjIHVzZSBhcHByb3ByaWF0ZSB0aXRsZQ0KICAgICAgIHN1YnRpdGxlID0gIkNvdW50aWVzIGluIE9yZWdvbiIsICMgdXNlIGFwcHJvcHJpYXRlIHN1YnRpdGxlDQogICAgICAgY2FwdGlvbiA9ICJEYXRhIGFjcXVpcmVkIHdpdGggUiBhbmQgdGlkeWNlbnN1cy4gRXJyb3IgYmFycyByZXByZXNlbnQgbWFyZ2luIG9mIGVycm9yIGFyb3VuZCBlc3RpbWF0ZXMuIiwNCiAgICAgICAiQUNTIGVzdGltYXRlIiwNCiAgICAgIHkgPSAiIiwNCiAgICAgIHggPSAiUGVyY2VudGFnZSIpICsNCiAgdGhlbWVfbWluaW1hbChiYXNlX3NpemUgPSAxMikgIyByZW1vdmUgdGljayBtYXJrcyANCiAgDQpvcl9wbG90X2Vycm9yYmFyICMgcHJpbnQgcGxvdA0KYGBgDQoqKkZpZ3VyZSAzKiogYWJvdmUgcmV2ZWFscyB0aGUgbWFyZ2luIG9mIGVycm9yIGFzc29jaWF0ZWQgd2l0aCB0aGUgZXN0aW1hdGUgZGF0YS4NCg0KPGhyIC8+DQoNCiMjIyBJbnRlcmF0aXZlIFBsb3RzDQoNCiMjIyMjIFVzaW5nIGdncGxvdGx5KCkgSSdtIGdvaW5nIHRvIHJlY3JlYXRlIHRoZSBwbG90IGFib3ZlIGJ1dCBsZXZlcmFnaW5nIHRoZSBpbnRlcmFjdGl2aXR5IG9mIHRoZSBwbG90bHkgbGlicmFyeS4NCmBgYHtyIGZpZy5oZWlnaHQ9NiwgZmlnLndpZHRoPTkuNX0NCiMgdXNlIGdncGxvdGx5KCkgYW5kIGFkZCBhIHRvb2x0aXAsIGFuZCBleHRlbmQgdGhlIG1hcmdpbnMgb2YgdGhlIHBsb3QNCmdncGxvdGx5KG9yX3Bsb3RfZXJyb3JiYXIsIHRvb2x0aXAgPSAieCIpJT4lIA0KICBsYXlvdXQobWFyZ2luID0gbGlzdChsID0gNTAsIHIgPSA1MCwgYiA9IDUwLCB0ID0gNTApKQ0KYGBgDQoqKkZpZ3VyZSA0KiogSG92ZXIgb3ZlciB0aGUgcG9pbnRzIGluIHRoZSBwbG90IGFib3ZlIHRvIHNlZSB0aGUgaW50ZXJhY3RpdmUgdG9vdGlwLg0KDQo8aHIgLz4NCg0KIyMjIFBhcnQgQg0KDQo8aHIgLz4NCg0KIyMjIyMgQ29udGludWluZyB3aXRoIHRoZSB0aGVtZSBvZiBlZHVjYXRpb24sIGxldHMgaW1wb3J0IG1vcmUgZGF0YSB0aHJvdWdoIHRoZSB0aWR5Y2Vuc3VzIHBhY2thZ2UuIA0KDQojIyMjIyA8c3Ryb25nPldoYXQgcGVyY2VudGFnZSBvZiBwZW9wbGUgd2l0aCBiYWNoZWxvcidzIGRlZ3JlZXMgcmVudCBvciBvd24gdGhlaXIgaG9tZSBpbiBXYXNoaW5ndG9uIGFuZCBNdWx0bm9tYWggQ291bnR5LCBPcmVnb24gYXQgdGhlIHRyYWN0IGxldmVsPzwvc3Ryb25nPg0KDQojIyMjIyBUaGVzZSB0d28gY291bnRpZXMgdG9nZXRoZXIgY292ZXIgdGhlIG1vc3QgcG9wdWx1cyBjaXR5IG9mIE9yZWdvbi4gWW91IGd1ZXNzZWQgaXQsIFBvcnRsYW5kLg0KDQojIyMjIyBUbyBmaW5kIHZhcmlhYmxlcyB0aGF0IHdpbGwgYXNzaXN0IHVzIGluIG91ciBhbmFseXNpcywgd2Ugd2lsbCB1c2UgdGhlIGxvYWRfdmFyaWFibGVzKCkgZnVuY3Rpb24gdG8gZmlsdGVyIHRocm91Z2ggdGhlIEFDUyBkYXRhLiANCmBgYHtyIG1lc3NhZ2UgPSBGQUxTRSwgd2FybmluZyA9IEZBTFNFfQ0KIyB1c2UgdGhlIGxvYWRfdmFyaWFibGVzIGZ1bmN0aW9uKCkgd2l0aCB0aGUgeWVhciBhbmQgQUNTIDUgeWVhciBwYXJhbWV0ZXINCnZhcnMgPC0gbG9hZF92YXJpYWJsZXMoMjAyMSwgImFjczUiKQ0KIyBsb2FkIHZhcnMgaW50byBhIGRhdGF0YWJsZQ0KZGF0YXRhYmxlKHZhcnMpDQpgYGANCioqRmlndXJlIDUqKiBCeSB1c2luZyB0aGUgc2VhcmNoIGZlYXR1cmUgaW4gdGhlIGRhdGF0YWJsZSwgeW91IHNlZSBleGFtcGxlcyBvZiBhdmFpbGFibGUgcmVzdWx0cy4gRm9yIGV4YW1wbGUgc2VhcmNoICJiYWNoZWxvcidzIiB0byBmaW5kIHZhcmlhYmxlIGNvZGVzIG1vdmluZyBmb3J3YXJkLiANCg0KPGhyIC8+DQoNCiMjIyBJbXBvcnQgRGF0YQ0KDQojIyMjIyBXZSB3aWxsIG5lZWQgdG8gcHVsbCBpbiB0d28gZGF0YXNldHMgYW5kIGV2ZW50dWFsbHkgbWVyZ2UgdGhlIHJlc3VsdHMgaW50byBvbmUgdGFibGUuIA0KIyMjIyMgIkIyNTAxM18wMDYiIGlzIHRoZSBwb3B1bGF0aW9uIG9mIHBlb3BsZSB3aXRoIGJhY2hlbG9yJ3MgZGVncmVlcyB0aGF0IG93biB0aGVpciBob21lLg0KIyMjIyMgIkIyNTAxM18wMTEiIGlzIHRoZSBwb3B1bGF0aW9uIG9mIHBlb3BsZSB3aXRoIGJhY2hlbG9yJ3MgZGVncmVlcyB0aGF0IHJlbnQgdGhlaXIgaG9tZS4NCmBgYHtyIG1lc3NhZ2UgPSBGQUxTRSwgd2FybmluZyA9IEZBTFNFfQ0KIyBpbXBvcnQgZGF0YSBhdCB0aGUgdHJhY3QgbGV2ZWwgZm9yIGhvbWUgb3duZXJzDQpiYWNoX293bmVycyA8LSBlcmFzZV93YXRlcihnZXRfYWNzKA0KICBnZW9ncmFwaHkgPSAidHJhY3QiLA0KICB2YXJpYWJsZXMgPSAiQjI1MDEzXzAwNiIsDQogIHN0YXRlID0gIk9SIiwNCiAgY291bnR5ID0gYygiV2FzaGluZ3RvbiIsICJNdWx0bm9tYWgiKSwgIyBzZWxlY3QgbXVsdGlwbGUgY291bnRpZXMNCiAgZ2VvbWV0cnkgPSBUUlVFLCAjIGdldCBtdWx0aXBvbHlnb24gZGF0YSBvZiBPcmVnb24gdHJhY3RzDQogIHByb2dyZXNzX2JhciA9IEZBTFNFDQopKQ0KDQojIGltcG9ydCBkYXRhIGF0IHRoZSB0cmFjdCBsZXZlbCBmb3IgcmVudGVycw0KYmFjaF9yZW50ZXJzIDwtIGdldF9hY3MoDQogIGdlb2dyYXBoeSA9ICJ0cmFjdCIsDQogIHZhcmlhYmxlcyA9ICJCMjUwMTNfMDExIiwNCiAgc3RhdGUgPSAiT1IiLA0KICBjb3VudHkgPSBjKCJXYXNoaW5ndG9uIiwgIk11bHRub21haCIpLCAjIHNlbGVjdCBtdWx0aXBsZSBjb3VudGllcw0KICBnZW9tZXRyeSA9IEZBTFNFLCAjIGdlb21ldHJ5IGlzIGZhbHNlIGJlY2F1c2Ugd2UgYXJlIGdldHRpbmcgb3VyIG11bHRpcG9seWdvbiBkYXRhIGluIHRoZSBvd25lcnMgZGF0YXNldC4gDQogIHByb2dyZXNzX2JhciA9IEZBTFNFDQogICkNCmBgYA0KIyMjIERhdGEgV3JhbmdsaW5nDQoNCiMjIyMjIFVzZSBmdW5jdGlvbnMgb2YgdGhlIHRpZHl2ZXJzZSB0byByZW5hbWUsIHNlbGVjdCwgYW5kIG11dHVhdGUgY29sdW1ucyB0byBmaXQgb3VyIGFuYWx5c2lzLiBTaW5jZSB0aGUgZXN0aW1hdGUgZGF0YSBvcmlnaW5hbGx5IGNvbWVzIGFzIGEgY291bnQsIHdlIHdpbGwgc3VtIHVwIHJlbnRlcnMgYW5kIG93bmVycyB0byBhIGNyZWF0ZSBhIHRvdGFsIGNvbHVtbiBhbmQgYSBwZXJjZW50YWdlIGNvbHVtbiBmb3IgZWFjaC4NCmBgYHtyIG1lc3NhZ2UgPSBGQUxTRSwgd2FybmluZyA9IEZBTFNFfQ0KIyBjbGFyaWZ5IHRoZSBuYW1lIG9mIHRoZSBlc3RpbWF0ZSAmIG1vZSBjb2x1bW5zIGJlZm9yZSBqb2luaW5nDQpiYWNoX293bmVycyA8LSBiYWNoX293bmVycyAlPiUNCiAgcmVuYW1lKGVzdGltYXRlX293bmVycyA9IGVzdGltYXRlLCBtb2Vfb3duZXJzID0gbW9lKQ0KDQojIGNsYXJpZnkgdGhlIG5hbWUgb2YgdGhlIGVzdGltYXRlICYgbW9lIGNvbHVtbnMgYmVmb3JlIGpvaW5pbmcNCmJhY2hfcmVudGVycyA8LSBiYWNoX3JlbnRlcnMgJT4lDQogIHJlbmFtZShlc3RpbWF0ZV9yZW50ZXJzID0gZXN0aW1hdGUsIG1vZV9yZW50ZXJzID0gbW9lKSAlPiUNCiAgc2VsZWN0KEdFT0lELCBlc3RpbWF0ZV9yZW50ZXJzLCBtb2VfcmVudGVycykgIyBkcm9wIHVubmVjZXNzYXJ5IHZhbHVlcw0KDQojIGpvaW4gZGF0YWZyYW1lcyBvbiBHRU9JRCwgYW5kIGNyZWF0ZSBwZXJjZW50IGNvbHVtbnMgb2YgZWFjaCBjYXRlZ29yeQ0KYmFjaF9ob3VzaW5nIDwtIGxlZnRfam9pbihiYWNoX293bmVycywgYmFjaF9yZW50ZXJzLCBieT0nR0VPSUQnKSAlPiUNCiAgc2VsZWN0KEdFT0lELCBOQU1FLCBlc3RpbWF0ZV9vd25lcnMsIGVzdGltYXRlX3JlbnRlcnMsIG1vZV9vd25lcnMsIG1vZV9yZW50ZXJzLCBnZW9tZXRyeSkgJT4lDQogIG11dGF0ZShlc3RpbWF0ZV90b3RhbCA9IGVzdGltYXRlX3JlbnRlcnMgKyBlc3RpbWF0ZV9vd25lcnMpICU+JSAjIGNyZWF0ZSBhIHRvdGFsIHZhbHVlDQogIG11dGF0ZShwZXJjZW50X3JlbnRlcnMgPSAoZXN0aW1hdGVfcmVudGVycy9lc3RpbWF0ZV90b3RhbCkqMTAwKSAlPiUgIyBjcmVhdGUgYSAlIG9mIHJlbnRlcnMNCiAgbXV0YXRlKHBlcmNlbnRfb3duZXJzID0gKGVzdGltYXRlX293bmVycy9lc3RpbWF0ZV90b3RhbCkqMTAwKSAlPiUgIyBjcmVhdGUgYSAlIG9mIG93bmVycw0KICBtdXRhdGUoYWNyb3NzKHdoZXJlKGlzLm51bWVyaWMpLCB+IHJvdW5kKC54LCBkaWdpdHMgPSAyKSkpDQpgYGANCiMjIyBEYXRhIFZpc3VhbGl6YXRpb24gJiBBbmFseXNpcw0KDQojIyMjIyBOb3cgdGhhdCB0aGUgZGF0YSBpcyB3cmFuZ2xlZCB3ZSBjYW4gdmlldyBpdCBpbiBhIHRhYmxlIGJlZm9yZSBtYXBwaW5nIGFuZCBwbG90dGluZyB0aGUgZGVzaXJlZCB2YXJpYWJsZXMuIA0KYGBge3IsIGZpZy5oZWlnaHQ9NiwgZmlnLndpZHRoPTkuNSwgbWVzc2FnZSA9IEZBTFNFLCB3YXJuaW5nID0gRkFMU0V9DQojIHNlbGVjdCBwZXJjZW50IHJlbnRlcnMgYW5kIG93bmVycw0KYmFjaF9ob3VzaW5nX3RhYmxlIDwtIGJhY2hfaG91c2luZyAlPiUNCiAgc2VsZWN0KE5BTUUsIHBlcmNlbnRfcmVudGVycywgcGVyY2VudF9vd25lcnMpICU+JQ0KICBhcnJhbmdlKC1wZXJjZW50X3JlbnRlcnMpICMgYXJyYW5nZSBpbiBkZXNjZW5kaW5nIG9yZGVyDQoNCiMgcHJldmlldyBpbiBkYXRhdGFibGUNCmRhdGF0YWJsZShiYWNoX2hvdXNpbmdfdGFibGUpDQpgYGANCioqRmlndXJlIDYqKiBBcyBzdXNwZWN0ZWQgaW4gUG9ydGxhbmQgdGhlcmUgYXJlIGEgaGlnaCBudW1iZXIgb2YgcmVudGVycyB3aXRoIGJhY2hlbG9yJ3MgZGVncmVlcy4gTXVsdGlwbGUgdHJhY3RzIHJldmVhbCBhcmVhcyB3aXRoIDEwMCUgb2Ygb3VyIHBhcnRpY3VsYXIgc3R1ZHkgcmVudCB0aGVpciBob21lcy4gDQoNCiMjIyMjIFdlIGFyZSBnb2luZyB0byBzdGFydCB3aXRoIHRoZSBtYXB2aWV3IHBhY2thZ2UgdG8gZ2V0IGEgZ2xpbXBsc2UgaW50byB0aGUgZGF0YS4NCmBgYHtyICxmaWcuaGVpZ2h0PTYsIGZpZy53aWR0aD05LjV9DQojIHVzZSB0aGUgcGVyY2VudF9yZW50ZXJzIHZhcmlhYmxlIHRvIGRpc3BsYXkgaW4gdGhlIG1hcHZpZXcNCm1hcHZpZXcoYmFjaF9ob3VzaW5nLA0KICAgICAgICBsYXllci5uYW1lID0gIiUgUmVudGVyczxici8+MjAxNy0yMDIxIEFDUyIsICMgY2hhbmdlIGxheWVyIG5hbWUNCiAgICAgICAgemNvbCA9ICJwZXJjZW50X3JlbnRlcnMiKSAjIHNlbGVjdCBhIHZhcmlhYmxlIHRvIGRpc3BsYXkNCmBgYA0KKipGaWd1cmUgNyoqIE1hcHZpZXcgaXMgcHJvZ3JhbW10aWNhbGx5IGEgc2ltcGxlIHdheSB0byBkaXNwbGF5IGluc2lnaHRmdWwgYW5kIGludGVyYWN0aXZlIGRhdGEuIFdlIGNhbiBub3cgZWFzaXkgdmlzdWFsaXplIHRoYXQgdGhlIGNpdHkgY2VudGVyIGhhcyB0aGUgaGlnaGVzdCBudW1iZXIgb2YgcmVudGVycyB2ZXJzdXMgb3duZXJzIGFuZCBzaGlmdHMgYXMgeW91IG1vdmUgaW50byB0aGUgbW9yZSBydXJhbCBhcmVhcy4NCg0KIyMjIyMgTm93IHRoYXQgd2UgaGF2ZSBzYW1wbGVkIHRoZSBkYXRhIGluIG1hcHZpZXcsIGxldHMgdXNlIGdncGxvdCB0byBjcmVhdGUgYSBzZXQgb2YgY2hsb3JvcGxldGggbWFwcyBmb3IgYm90aCBjYXRlZ29yaWVzIChyZW50aW5nIGFuZCBvd25pbmcpLiANCmBgYHtyLCBmaWcuaGVpZ2h0PTgsIGZpZy53aWR0aD05LjV9DQojIGNyZWF0ZSBnZ3Bsb3QgZm9yIHJlbnRlcnMNCnJlbnRlcnMgPC0gZ2dwbG90KGJhY2hfaG91c2luZywgYWVzKGZpbGwgPSBwZXJjZW50X3JlbnRlcnMpKSArICMgZmlsbCB3aXRoIHBlcmNlbnQgcmVudGVycw0KICBnZW9tX3NmKCkgKyANCiAgdGhlbWVfdm9pZCgpICsgDQogIHNjYWxlX2ZpbGxfdmlyaWRpc19jKG9wdGlvbiA9ICJyb2NrZXQiKSArICMgdXNlIHJvY2tldCBjb2xvciBzY2hlbWUNCiAgbGFicyh0aXRsZSA9ICJQZXJjZW50IG9mIFBvcHVsYXRpb24gdy8gQmFjaGVsb3IncyBEZWdyZWUgUmVudGluZyBieSBDZW5zdXMgdHJhY3QiLCAjIGNyZWF0ZSBjbGVhciB0aXRsZXMgYW5kIGNhcHRpb25zDQogICAgICAgc3VidGl0bGUgPSAiV2FzaGluZ3RvbiAmIE11bHRub21haCBDb3VudHksIE9yZWdvbiIsDQogICAgICAgZmlsbCA9ICIlIFJlbnRpbmciLA0KICAgICAgIGNhcHRpb24gPSAiMjAxNy0yMDIxIEFDUyB8IHRpZHljZW5zdXMgUiBwYWNrYWdlIikNCg0KIyBjcmVhdGUgZ2dwbG90IGZvciBvd25lcnMNCm93bmVycyA8LSBnZ3Bsb3QoYmFjaF9ob3VzaW5nLCBhZXMoZmlsbCA9IHBlcmNlbnRfb3duZXJzKSkgKyANCiAgZ2VvbV9zZigpICsgDQogIHRoZW1lX3ZvaWQoKSArIA0KICBzY2FsZV9maWxsX3ZpcmlkaXNfYyhvcHRpb24gPSAicm9ja2V0IikgKyAgIyB1c2Ugcm9ja2V0IGNvbG9yIHNjaGVtZQ0KICBsYWJzKHRpdGxlID0gIlBlcmNlbnQgb2YgUG9wdWxhdGlvbiB3LyBCYWNoZWxvcidzIERlZ3JlZSBUaGF0IE93biBUaGVpciBIb21lIGJ5IENlbnN1cyB0cmFjdCIsICAjIGNyZWF0ZSBjbGVhciB0aXRsZXMgYW5kIGNhcHRpb25zDQogICAgICAgc3VidGl0bGUgPSAiV2FzaGluZ3RvbiAmIE11bHRub21haCBDb3VudHksIE9yZWdvbiIsDQogICAgICAgZmlsbCA9ICIlIE93bmVycyIsDQogICAgICAgY2FwdGlvbiA9ICIyMDE3LTIwMjEgQUNTIHwgdGlkeWNlbnN1cyBSIHBhY2thZ2UiKQ0KDQojIHVzZSBwbG90X2dyaWQgZnJvbSB0aGUgY293cGxvdCBsaWJyYXJ5IHRvIHN0YWNrIHRoZSBtYXBzDQpwbG90X2dyaWQocmVudGVycywgb3duZXJzLCBuY29sPTEsIGFsaWduID0gImh2IikNCmBgYA0KKipGaWd1cmUgOCoqIFRoZSBsYXN0IGZpZ3VyZSBwYWludHMgYSBjbGVhciBwaWN0dXJlIG9mIHRoZSBjaXR5IGNlbnRlciB2cyBydXJhbCBhcmVhcyBpbiB0ZXJtcyBvZiB0aGUgYWJpbGl0eSB0byBvd24gYSBob21lIGluIHRoZSBQb3J0bGFuZCBNZXRybyBhcmVhLiANCg0KPGhyIC8+DQo8aHIgLz4=